﻿Imports Microsoft.VisualBasic

Namespace SimilText

    Public Class ArchiveData

        Public Property ArchiveID As Integer

        Public Property Dictionary As Dictionary
        Public Property Stemming As Dictionary
        Public Property Stopword As Dictionary

        Public Property IndexesPathBase As String = "\SimilText\Indexes\" ' HttpContext.Current.Server.MapPath("~/App_Data/Indexes/")
        Public Property IndexesPath As String ' = HttpContext.Current.Server.MapPath("~/App_Data/Indexes/")
        Public Property CommonPath As String = "\SimilText\Common\" 'HttpContext.Current.Server.MapPath("~/App_Data/Common/")

        Public Property BlockSize As Integer = 1024 * 1024 * 50 ' (10M)
        Public Property ArchiveFile As String = "Archive.dat"
        Public Property DicFile As String = "Dic.dat"
        Public Property IndexFile As String = "Attr.inx"
        Public Property StopWordsFile As String = "stopwords_{0}.txt"
        Public Property StemmingFile As String = "stemming_{0}.txt"

        Public Property AttribNumber As Integer = 2
        Public Property ThreadNumber As Integer = 2

        Public Property Rank_word_word As Integer = 100
        Public Property Rank_word_hashtag As Integer = 120
        Public Property Rank_Hashtag_hashtag As Integer = 140 '%
        Public Property Rank_Hashtag_word As Integer = 80 '%
        Public Property Rank_stemming As Integer = 70 '%
        Public Property Rank_word_prox As Integer = 30

        Public Property TextElementFixedSize As Integer

        'indice
        Public Property NumMaxBlock As Integer = 100
        Public Property RefBlockSize As Integer = 8

        Public Shared Function GetData(id As Integer) As ArchiveData

            Dim c = HttpContext.Current.Cache
            Dim Data As ArchiveData
            Dim Key = "index_data_" & id.ToString

            Data = c(Key)

            If Data Is Nothing Then

                Utils.GC.WaitFinalizers()
                Data = New SimilText.ArchiveData(id)
                c.Insert(Key, Data, Nothing, System.Web.Caching.Cache.NoAbsoluteExpiration, New TimeSpan(0, 5, 0))

            End If

            Return Data

        End Function
        Public Shared Sub RemoveData(id As Integer)


            Dim Data = SimilText.ArchiveData.GetData(id)


            Dim c = HttpContext.Current.Cache
            Dim Key = "index_data_" & id.ToString

            c.Remove(Key)

            'rimuovi i file
            Data.RemoveFile()
            'IO.Directory.Delete(Data.IndexesPath, True)



        End Sub


        Public Function GetIndexesPath() As String

            Dim IndexesPath = Me.IndexesPathBase
            ' crea path dell indice
            Dim IdStr = Me.ArchiveID.ToString
            If IdStr.Length Mod 2 = 1 Then
                IdStr = "0" & IdStr
            End If

            For ct = 0 To (IdStr.Length) / 2 - 1
                IndexesPath &= IdStr.Substring(ct * 2, 2) & "\"
            Next

            Return IndexesPath

        End Function

        Public Sub RemoveFile()

            IO.File.Delete(IndexesPath & ArchiveFile)
            IO.File.Delete(IndexesPath & DicFile)
            IO.File.Delete(IndexesPath & IndexFile)

        End Sub


        Public Sub New(ID As Integer)

            Me.ArchiveID = ID

            TextElementFixedSize = 4 + (AttribNumber * 4) + (AttribNumber * 4) + 4
            'Dim Folder = ArchiveData

            'folder
            Dim RootPath = IO.Directory.CreateDirectory(HttpContext.Current.Server.MapPath("~/")).Parent.FullName
            Me.IndexesPathBase = RootPath & Me.IndexesPathBase
            Me.CommonPath = RootPath & Me.CommonPath
            Me.IndexesPath = Me.GetIndexesPath

            'verifico l'esistenza dei file e cartelle base
            If Not IO.Directory.Exists(IndexesPath) Then
                IO.Directory.CreateDirectory(IndexesPath)
            End If

            If Not IO.File.Exists(IndexesPath & ArchiveFile) Then
                IO.File.Create(IndexesPath & ArchiveFile).Close()
            End If

            If Not IO.File.Exists(IndexesPath & DicFile) Then
                IO.File.Create(IndexesPath & DicFile).Close()
            End If

            If Not IO.File.Exists(IndexesPath & IndexFile) Then
                IO.File.Create(IndexesPath & IndexFile).Close()
                ArchiveIndex.CreateHeaders(Me)
            End If

            'crea tutti i dic
            If Me.Stemming Is Nothing Then
                Me.Stemming = SimilText.Dictionary.GetStemming(CommonPath & StemmingFile)
            End If

            If Me.Stopword Is Nothing Then
                Me.Stopword = SimilText.Dictionary.GetStopWord(CommonPath & StopWordsFile)
            End If

            If Dictionary Is Nothing Then
                Dictionary = New Dictionary()
                'IMPORTANTE aggiunge sempre come dic di base lo stemming
                Dictionary.DicBase = Me.Stemming

                Dictionary.LoadDictionary(IndexesPath & DicFile, SimilText.Dictionary.FormatType.BIN)

            End If

            'If Me.Gender Is Nothing Then
            '    Me.Gender = New DictionaryGender
            'End If


        End Sub


    End Class

    ' IMPORTANTE indica la seguenza si salvataggio su file
    'Public Enum ArchiveIndexType
    '    Attribute1 = 0
    '    Attribute2 = 1
    'End Enum

    Public Class ArchiveIndex
        'Inherits Dictionary(Of Integer, Dictionary(Of Integer, ArchiveIndexElement))
        Structure IndexBlockData
            Dim Ref As Integer
            Dim Lenght As Integer
        End Structure

        Public Property Values As New Dictionary(Of Integer, Integer)
        Public Property ValuesList As ArchiveIndexElement()
        'Public Property SortIndex As New List(Of KeyValuePair(Of Integer, Dictionary(Of Integer, ArchiveIndexElement)))
        Public Property IndexType As Integer ' ArchiveIndexType
        'Public Property FIndex As IO.BinaryWriter
        Public Property IndexFile As String

        Public Property BlockIndex As IndexBlockData()
        Public Property NBlock As Integer



        Private AD As ArchiveData
        Public Shared Sub CreateHeaders(AD As ArchiveData)

            Dim FIndex = New IO.BinaryWriter(New IO.FileStream(AD.IndexesPath & AD.IndexFile, IO.FileMode.Open, IO.FileAccess.Write, IO.FileShare.Read))

            FIndex.BaseStream.Seek(0, IO.SeekOrigin.Begin)

            For ct = 0 To (AD.AttribNumber * AD.NumMaxBlock) - 1
                FIndex.Write(CInt(0))
                FIndex.Write(CInt(0))

            Next

            FIndex.Close()

        End Sub

        Public Sub New(AD As ArchiveData, ByVal IndexType As Integer, NBlock As Integer)
            Me.AD = AD
            Me.IndexType = IndexType
            Me.IndexFile = AD.IndexesPath & AD.IndexFile
            Me.NBlock = NBlock

            Me.Load()

        End Sub

        'Public Sub New(ByVal AD As ArchiveData, ByVal IndexType As Integer)

        '    Me.AD = AD

        '    Me.Load(AD.IndexesPath & SF(AD.IndexFileAttr, IndexType))

        '    'Select Case IndexType

        '    '    Case ArchiveIndexType.Attribute1
        '    '        Me.Load(AD.IndexesPath & AD.IndexFileAttr0)

        '    '    Case ArchiveIndexType.Attribute2
        '    '        Me.Load(AD.IndexesPath & AD.IndexFileAttr1)

        '    'End Select

        '    Me.IndexType = IndexType

        'End Sub
        Public Sub ListToDic()

            For ct = 0 To Me.ValuesList.Length - 1
                Me.Values.Add(Me.ValuesList(ct).Value, ct)
            Next

        End Sub

        Public Sub Load()

            ' carico l'indice
            Dim Buff() As Byte = {}
            Dim LenFile As Integer
            Dim TotalKey As Integer

            Dim FIndex As New IO.BinaryReader(New IO.FileStream(Me.IndexFile, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read))
            LenFile = FIndex.BaseStream.Length

            'carica i puntatori ai blocci
            Me.LoadRefBlock(FIndex)

            ' carica il blocco di indici
            Me.LoadBlockFile(FIndex, Buff)

            'crea struttura in memoria
            TotalKey = Buff.Length / ArchiveIndexElement.FixedSize
            ReDim Me.ValuesList(TotalKey - 1)
            Dim i = 0
            For ct As Integer = 0 To TotalKey - 1
                Dim IndexElem As New ArchiveIndexElement
                IndexElem.Load(Buff, i)
                Me.ValuesList(ct) = IndexElem
            Next

            FIndex.Close()

        End Sub
        Private Sub LoadRefBlock(ByVal f As IO.BinaryReader)

            'carica i puntatori ai blocci
            ReDim Me.BlockIndex(AD.NumMaxBlock - 1)

            f.BaseStream.Seek(Me.IndexType * AD.NumMaxBlock * AD.RefBlockSize, IO.SeekOrigin.Begin)
            For ct = 0 To AD.NumMaxBlock - 1
                Me.BlockIndex(ct).Ref = f.ReadInt32
                Me.BlockIndex(ct).Lenght = f.ReadInt32
            Next

        End Sub
        Private Sub LoadBlockFile(ByVal f As IO.BinaryReader, ByRef Buff() As Byte)

            Dim LenFile As Integer = f.BaseStream.Length
            Dim Start = Me.BlockIndex(NBlock).Ref
            Dim DataLen = Me.BlockIndex(NBlock).Lenght

            ReDim Buff(DataLen)

            SyncLock f
                f.BaseStream.Seek(Start, IO.SeekOrigin.Begin)
                f.Read(Buff, 0, DataLen)
            End SyncLock

        End Sub

        Public Sub Save()

            Me.ValuesList = Me.ValuesList.Take(Me.Values.Count).OrderBy(Function(o) o.Value).ToArray()

            Dim FIndex = New IO.BinaryWriter(New IO.FileStream(IndexFile, IO.FileMode.Open, IO.FileAccess.ReadWrite, IO.FileShare.Read))

            'IMPORTANTE leggo i puntatori ai blocchi per capire dove salvare
            Me.LoadRefBlock(New IO.BinaryReader(FIndex.BaseStream))

            Me.SaveBlockFile(FIndex)

            Me.SaveRefBlock(FIndex)

            FIndex.Close()

        End Sub
        Private Sub SaveRefBlock(ByVal f As IO.BinaryWriter)

            'salva i puntatori ai blocci
            f.BaseStream.Seek(Me.IndexType * AD.NumMaxBlock * AD.RefBlockSize, IO.SeekOrigin.Begin)
            For ct = 0 To AD.NumMaxBlock - 1
                f.Write(Me.BlockIndex(ct).Ref)
                f.Write(Me.BlockIndex(ct).Lenght)
            Next

            'IMPORTANTE se eiste un attributo dopo cambia la pos
            If (Me.IndexType + 1) <= AD.AttribNumber - 1 Then
                f.BaseStream.Seek((Me.IndexType + 1) * AD.NumMaxBlock * AD.RefBlockSize + (Me.NBlock * AD.RefBlockSize), IO.SeekOrigin.Begin)
                f.Write(Me.BlockIndex(Me.NBlock).Ref + Me.BlockIndex(Me.NBlock).Lenght)
            End If


        End Sub
        Private Sub SaveBlockFile(ByVal f As IO.BinaryWriter)

            If Me.BlockIndex(NBlock).Ref = 0 Then
                Me.BlockIndex(NBlock).Ref = f.BaseStream.Length
            End If

            Me.BlockIndex(NBlock).Lenght = Me.ValuesList.Length * ArchiveIndexElement.FixedSize

            Dim Start = Me.BlockIndex(NBlock).Ref

            f.BaseStream.Seek(Start, IO.SeekOrigin.Begin)

            For ct = 0 To Me.ValuesList.Length - 1
                Me.ValuesList(ct).Save(f)
            Next

        End Sub



        'Public Sub AddElementFromData(ByRef Buffer() As Byte, ByVal Start As Integer)

        '    Dim IndexElem As New ArchiveIndexElement
        '    'AE.Modified = False
        '    Dim k As Integer = IndexElem.Load(Buffer, Start)


        '    If Not Me.ContainsKey(k) Then
        '        Me.Add(k, New Dictionary(Of Integer, ArchiveIndexElement))
        '    End If
        '    '
        '    Me(k).Add(Int(IndexElem.FirstTextRef / Me.AD.BlockSize), IndexElem)


        'End Sub

        ''Public Sub SortedIndex()

        '    ' ordino tutti gli elemnti
        '    SortIndex = Me.OrderBy(Function(o) o.Key).ToList

        'End Sub

        'Public Function FindKey(ByVal k As Integer) As Integer

        '    Dim min As Integer = 0
        '    Dim max As Integer = SortIndex.Count - 1
        '    Dim p As Integer
        '    Dim trovato As Boolean = False


        '    Do

        '        p = (max + min) / 2
        '        If SortIndex(p).Key > k Then
        '            max = p
        '        ElseIf SortIndex(p).Key < k Then
        '            min = p
        '        Else
        '            trovato = True
        '        End If

        '    Loop Until trovato Or max - min = 1

        '    If Not trovato Then
        '        If SortIndex(max).Key >= k Then
        '            p = max
        '        Else
        '            p = -1
        '        End If
        '        If SortIndex(min).Key >= k Then
        '            p = min
        '        End If
        '    End If


        '    Return p

        'End Function


        Public Function FindNextPos(ByRef CurrPos As Integer, ValueMin As Integer, ValueMax As Integer) As UInteger
            Dim i As UInteger = UInteger.MaxValue

            ' se non esiste una posiszione attuale cerpa la posizione iniziale
            If CurrPos = -1 Then
                CurrPos = Me.FindKeyArr(ValueMin)
            Else
                CurrPos += 1
            End If

            ' se la posizioni corrente rimane indefinita non cerca nemmeno quella sucessiva
            If CurrPos <> -1 Then
                Do Until CurrPos > Me.ValuesList.Length - 1
                    'verifica se la key è dentro al filtro massimo
                    If Me.ValuesList(CurrPos).Value <= ValueMax Then
                        'verifico che esista di questa key dati nel blocco corrente
                        i = Me.ValuesList(CurrPos).FirstTextRef
                        'If Me.Index.ValuesList(CurrPos).Value.ContainsKey(NumBlock) Then
                        'i = Me.Index.ValuesList(CurrPos).Value(NumBlock).FirstTextRef
                        Exit Do
                        'End If
                    End If
                    CurrPos += 1
                Loop
            End If

            Return i

        End Function
        Public Function FindKeyArr(ByVal k As Integer) As Integer

            Dim SortIndex = Me.ValuesList

            Dim min As Integer = 0
            Dim max As Integer = SortIndex.Count - 1
            Dim p As Integer
            Dim trovato As Boolean = False


            Do

                p = (max + min) / 2
                If SortIndex(p).Value > k Then
                    max = p
                ElseIf SortIndex(p).Value < k Then
                    min = p
                Else
                    trovato = True
                End If

            Loop Until trovato Or max - min = 1

            If Not trovato Then
                If SortIndex(max).Value >= k Then
                    p = max
                Else
                    p = -1
                End If
                If SortIndex(min).Value >= k Then
                    p = min
                End If
            End If


            Return p

        End Function

    End Class
    Public Class ArchiveIndexElement

        Public Property Value As Integer

        Public Property FirstTextRef As UInteger
        'Public Property KeyPosition As UInteger

        Public Const FixedSize As Integer = 8

        Public Sub New()

        End Sub

        Public Sub Load(ByRef d() As Byte, ByRef Start As Integer)
            'Dim Key As Integer

            'Me.KeyPosition = Start

            Value = BitConverter.ToInt32(d, Start)
            Start += 4

            Me.FirstTextRef = BitConverter.ToUInt32(d, Start)
            Start += 4

            'Me.NextKeyRef = BitConverter.ToUInt32(d, Start)
            'Start += 4

            'Return Key

        End Sub

        Public Sub Save(ByRef fw As IO.BinaryWriter)

            ' si posiziona nel posto giusto
            'If Me.KeyPosition = UInteger.MaxValue Then
            'Me.KeyPosition = fw.BaseStream.Length
            'End If

            'fw.Seek(Me.KeyPosition, IO.SeekOrigin.Begin)

            ' scrivo l'id
            fw.Write(Me.Value)
            fw.Write(Me.FirstTextRef)
            'fw.Write(Me.NextKeyRef)

        End Sub
        'salva solo le referenze delle key
        'Public Sub SaveOnlyKeyRef(ByRef fw As IO.BinaryWriter)

        '    fw.Seek(Me.KeyPosition + 8, IO.SeekOrigin.Begin)

        'End Sub


    End Class

    Public Class ArchiveText

        Public Class AttributeText

            Public Value As Integer
            Public Index As ArchiveIndex

        End Class

        Public Property Folder As String
        Public Property Text As String
        Public Property Id As Integer
        Public Property Attributes As New List(Of AttributeText)

        Private DataTemp() As Byte
        Private FArchiveData As IO.BinaryWriter

        Private AD As ArchiveData

        Private CurrBlock, CurrBlockIndex As Integer

        Public Sub New(ByVal AD As ArchiveData)

            Me.AD = AD

            ReDim DataTemp(AD.BlockSize)
            Me.Folder = AD.IndexesPath

            'Dim a As AttributeText
            For ct = 0 To Me.AD.AttribNumber - 1

                Me.Attributes.Add(New AttributeText With {
                    .Value = 0
                })

            Next

            'forzo il ricarimanto degli indici
            Me.CurrBlockIndex = -1

            'apro i file
            FArchiveData = New IO.BinaryWriter(New IO.FileStream(Folder & AD.ArchiveFile, IO.FileMode.Open, IO.FileAccess.Write, IO.FileShare.Read))
            FArchiveData.Seek(0, IO.SeekOrigin.End)

        End Sub

        Private Sub SaveIndex()

            For ct = 0 To Me.AD.AttribNumber - 1

                If Me.Attributes(ct).Index IsNot Nothing Then
                    Me.Attributes(ct).Index.Save()
                End If

            Next

        End Sub

        Private Sub LoadIndex()

            For ct = 0 To Me.AD.AttribNumber - 1

                Dim Index = New ArchiveIndex(AD, ct, CurrBlockIndex)
                'IMPORTANTE quando archivio uso anche il dictionary
                Index.ListToDic()

                Me.Attributes(ct).Index = Index

            Next

        End Sub

        Public Sub EditAttribute(ByVal value As UInteger, ByVal IndexType As Integer)

            Me.Attributes(IndexType).Value = value

        End Sub

        Public Sub Archive()
            Dim t As New TextElement(Me.AD)
            Dim IndexAttr As ArchiveIndex
            Dim Attr As UInteger
            Dim index As ArchiveIndexElement

            If Text.Length = 0 Then Exit Sub

            'converte il testo in buffer
            'Dim d() As Byte = New TextTools(Me.Text, Me.TI).TextToBytes
            t.DataText = New TextTools(Me.Text, Me.AD).TextToNumber

            ' verifica se deve creare un blocco nuovo
            'If (FArchiveData.BaseStream.Length Mod TI.BlockSize) + TextElement.FixedSize + d.Length > TI.BlockSize Then
            If (FArchiveData.BaseStream.Length Mod AD.BlockSize) + Me.AD.TextElementFixedSize + (t.DataText.Length * 4) > AD.BlockSize Then
                Dim LenF As Long = FArchiveData.BaseStream.Length
                'IMPORTANTE metto un id di fine blocco, cmq lo spazio di almeno di 4 byte c'è
                FArchiveData.Write(UInteger.MaxValue)
                'metto il resto di un qualsiasi valore giusto per riempire il file
                FArchiveData.Write(DataTemp, 0, AD.BlockSize - (LenF Mod AD.BlockSize) - 4)
            End If

            'blocco corrente
            CurrBlock = Int((FArchiveData.BaseStream.Length) / AD.BlockSize)

            'se cambia il blobbo corrente automaticamente salva l'indice e li ricarica creandone di nuovi (serve anche per caricarli la prima volta
            If Me.CurrBlockIndex <> Me.CurrBlock Then
                Me.CurrBlockIndex = Me.CurrBlock
                If Me.CurrBlock <> 0 Then
                    Me.SaveIndex()
                End If
                Me.LoadIndex()
            End If

            'cicla i file indice possibili
            For ct As Integer = 0 To Me.Attributes.Count - 1
                IndexAttr = Me.Attributes(ct).Index
                Attr = Me.Attributes(ct).Value

                index = Nothing
                If IndexAttr.Values.ContainsKey(Attr) Then
                    index = IndexAttr.ValuesList(IndexAttr.Values(Attr))
                End If


                If index IsNot Nothing Then
                    ' modifica l'elemento testo da poi inserire
                    t.NextForAttributeRef(IndexAttr.IndexType) = index.FirstTextRef

                    'modifica l'indice in memoria
                    index.FirstTextRef = FArchiveData.BaseStream.Length


                Else
                    ' se non esiste si aggiunge 
                    'IMPORTANTE non metto i riferimenti alle altre key, aggiorno tutto dopo
                    index = New ArchiveIndexElement
                    index.FirstTextRef = FArchiveData.BaseStream.Length
                    index.Value = Attr

                    Dim LastPos = IndexAttr.Values.Count

                    If LastPos >= IndexAttr.ValuesList.Length Then
                        ReDim Preserve IndexAttr.ValuesList(IndexAttr.ValuesList.Length + 100000)
                    End If

                    IndexAttr.ValuesList(LastPos) = index
                    IndexAttr.Values.Add(Attr, LastPos)

                    ' mette un puntatore FINE del testo
                    t.NextForAttributeRef(IndexAttr.IndexType) = UInteger.MaxValue

                End If

                'salvo oggetto anche nel file indice
                'index.Save(Attr, IndexAttr.FIndex)

                t.Attributes(IndexAttr.IndexType) = Attr

            Next

            ' imposta i dati dell'elemnto testo e salva
            t.Id = Me.Id
            't.Save(FArchiveData, d)
            t.Save(FArchiveData)

        End Sub




        'Public Sub Open()
        '    ' apro in scrittuta gli indici
        '    FArchiveData = New IO.BinaryWriter(New IO.FileStream(Folder & AD.ArchiveFile, IO.FileMode.Open, IO.FileAccess.Write, IO.FileShare.Read))
        '    FArchiveData.Seek(0, IO.SeekOrigin.End)

        'End Sub

        Public Sub Close()

            'chiudo la scrittura dell'archivio
            FArchiveData.Close()

            'salva gli indici
            Me.SaveIndex()

            ' quando chiudo l'archiviazione forzo il salvataggio del dizionario
            Me.AD.Dictionary.SaveDictionary()

        End Sub
    
    End Class

    Public Class TextElement

        Public Property Id As UInteger
        Public Property DataText As UInteger()
        Public Property Attributes As UInteger()
        Public Property NextForAttributeRef As UInteger()



        Private AD As ArchiveData
        Public Sub New(AD As ArchiveData)

            Me.AD = AD

            ReDim Attributes(Me.AD.AttribNumber - 1)
            ReDim NextForAttributeRef(Me.AD.AttribNumber - 1)

        End Sub

        'Public Sub New(ByRef d() As Byte, ByRef Start As Integer)
        '    Me.New()

        '    Me.Load(d, Start)

        'End Sub

        Public Sub Load(ByRef d() As Byte, ByRef Start As Integer)
            Dim DataLength As UInteger

            ' leggo l'ID
            Me.Id = BitConverter.ToUInt32(d, Start)
            Start += 4

            If Me.Id <> UInteger.MaxValue Then

                For ct = 0 To Me.AD.AttribNumber - 1
                    ' leggo l'attr0
                    Me.Attributes(ct) = BitConverter.ToUInt32(d, Start)
                    Start += 4
                Next
                '' leggo l'attr0
                'Me.Attributes(0) = BitConverter.ToUInt32(d, Start)
                'Start += 4
                '' leggo la data
                'Me.Attributes(1) = BitConverter.ToUInt32(d, Start)
                'Start += 4

                For ct = 0 To Me.AD.AttribNumber - 1
                    Me.NextForAttributeRef(ct) = BitConverter.ToUInt32(d, Start)
                    Start += 4
                Next

                '' leggo puntatore prossimo atttributo
                'Me.NextForAttributeRef(0) = BitConverter.ToUInt32(d, Start)
                'Start += 4
                '' leggo puntatore prossimo data
                'Me.NextForAttributeRef(1) = BitConverter.ToUInt32(d, Start)
                'Start += 4

                ' leggo la lunghezza
                DataLength = BitConverter.ToUInt32(d, Start)
                Start += 4
                ' leggo i dati

                ReDim DataText(DataLength - 1)

                Buffer.BlockCopy(d, Start, DataText, 0, DataLength * 4)
                Start += DataLength * 4
            End If

        End Sub

        Public Sub Save(ByRef fw As IO.BinaryWriter) ', ByRef d() As Byte)

            ' scrivo l'id
            fw.Write(Me.Id)

            ' scrivo l'attr
            For ct = 0 To Me.AD.AttribNumber - 1
                fw.Write(Me.Attributes(ct))
            Next

            '' scrivo l'attr1
            'fw.Write(Me.Attributes(0))
            '' scrivo l'attr2
            'fw.Write(Me.Attributes(1))

            ' scrivo next punt attr
            For ct = 0 To Me.AD.AttribNumber - 1
                fw.Write(Me.NextForAttributeRef(ct))
            Next

            '' scrivo next punt attr
            'fw.Write(Me.NextForAttributeRef(0))
            '' scrivo next punt date
            'fw.Write(Me.NextForAttributeRef(1))

            ' scrivo la lunghezza
            fw.Write(Me.DataText.Length)

            ' scrivo i dati
            Dim DataByte((Me.DataText.Length * 4) - 1) As Byte
            Buffer.BlockCopy(Me.DataText, 0, DataByte, 0, Me.DataText.Length * 4)
            fw.Write(DataByte, 0, DataByte.Length)


        End Sub



    End Class
End Namespace
